package org.pfc.porlapatilla.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.pfc.porlapatilla.DTO.UserDTO;
import org.pfc.porlapatilla.model.User;
import org.pfc.porlapatilla.repositories.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * This service provides data management to UserController.
 * 
 * @author jorgepolobermudez
 * 
 */
@Service
public class UserService implements UserDetailsService {

    private static final Logger logger = LoggerFactory
	    .getLogger(UserService.class);

    /**
     * The UserRepository instance.
     */
    @Autowired
    private UserRepository userRepository;

    /**
     * Find all stored users.
     * 
     * @return The found users list.
     */
    public List<User> findAll() {
	return userRepository.findAll();
    }

    /**
     * Find all stored users.
     * 
     * @param page
     *            Page number.
     * @param size
     *            Size of page.
     * @return The list of <strong>size</strong> users in the page
     *         <strong>page</strong>.
     */
    public List<User> findAll(int page, int size) {
	Page<User> users = userRepository.findAll(new PageRequest(page, size));
	return users.getContent();
    }

    /**
     * Find stored user by id.
     * 
     * @param id
     *            The user id.
     * @return The found user.
     */
    public User findById(String id) {
	return userRepository.findById(id);
    }

    /**
     * Find stored user by email.
     * 
     * @param email
     *            The user email.
     * @return The found user.
     */
    public User findByEmail(String email) {
	return userRepository.findByEmail(email);
    }

    /**
     * Find stored user by nick.
     * 
     * @param nick
     *            The user nick.
     * @return The found user.
     */
    public User findByNick(String nick) {
	return userRepository.findByNick(nick);
    }

    /**
     * Store an user.
     * 
     * @param userDTO
     *            The user to store.
     * @return The stored user id.
     */
    public String store(UserDTO userDTO) {
	User user = new User();

	user.setAddress(userDTO.getAddress());
	user.setEmail(userDTO.getEmail());
	user.setName(userDTO.getName());
	user.setNick(userDTO.getNick());
	user.setPassword(userDTO.getPassword());
	user.setSurnname(userDTO.getSurname());
	
	List<String> roles = new ArrayList<String>(1);
	roles.add("ROLE_USER");
	
	user.setRoles(roles);

	return userRepository.save(user).getId();
    }
    
    /**
     * Updates an user
     * @param userDTO The user info to update
     * @return <code>true</code> if the user was updated, <code>false</code> otherwise 
     */
    public boolean update(UserDTO userDTO) {
	User user = userRepository.findByNick(userDTO.getNick());
	
	if (user == null) {
	    return false;
	}
	
	user.setAddress(userDTO.getAddress());
	user.setEmail(userDTO.getEmail());
	user.setName(userDTO.getName());
	user.setSurnname(userDTO.getSurname());
	
	userRepository.save(user);
	return true;
    }
    
    /**
     * Changes user password
     * @param userDTO The user info to change
     * @return <code>true</code> if user password was changed, <code>false</code> otherwise
     */
    public boolean changeUserPassword(UserDTO userDTO) {
	User user = userRepository.findByNick(userDTO.getNick());
	
	if (user == null) {
	    return false;
	}

	user.setPassword(userDTO.getPassword());
	userRepository.save(user);
	return true;
    }
    
    /**
     * Returns user profile information
     * @param nick The user nick
     * @return The user profile information
     */
    public UserDTO getUserProfile(String nick) {
	User user = userRepository.findByNick(nick);
	
	if (user == null) {
	    return null;
	}
	
	UserDTO userDTO = new UserDTO();
	userDTO.setAddress(user.getAddress());
	userDTO.setEmail(user.getEmail());
	userDTO.setName(user.getName());
	userDTO.setNick(nick);
	userDTO.setSurname(user.getSurname());
	
	return userDTO;
    }

    /**
     * Implements UserDetailsService.loadUserByUsername().
     */
    //public UserDetails loadUserByUsername(String email)
    public UserDetails loadUserByUsername(String nick)
	    throws UsernameNotFoundException {

	//User userEntity = this.findByEmail(email);
	User userEntity = this.findByNick(nick);
	if (userEntity == null) {
	    logger.info("User not found");
	    throw new UsernameNotFoundException("User not found");
	}

	String username = userEntity.getNick();
	String password = userEntity.getPassword();
//	logger.info("User found: " + username);

	boolean enabled = true;
	boolean accountNonExpired = true;
	boolean credentialsNonExpired = true;
	boolean accountNonLocked = true;

	Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
	for (String rol : userEntity.getRoles()) {
	    authorities.add(new SimpleGrantedAuthority(rol));
	}

	org.springframework.security.core.userdetails.User user = 
		new org.springframework.security.core.userdetails.User(
			username, 
			password, 
			enabled, 
			accountNonExpired, 
			credentialsNonExpired, 
			accountNonLocked, 
			authorities);

	return user;
    }

}
